import * as fs from 'fs';
import * as path from 'path';
import { Logger } from '../../../src/logger/Logger';

/**
 * GN 文件智能更新器
 * 负责智能地更新现有 BUILD.gn 文件，而不是覆盖
 */
export class GNFileUpdater {
    /**
     * 更新或创建 unittest BUILD.gn
     * @param gnFilePath BUILD.gn 文件路径
     * @param testTargetName 测试目标名称（如 "cloud_daemon_manager_test"）
     * @param testTargetContent 测试目标的完整内容（ohos_unittest块）
     * @param groupName group 名称（如 "cloud_daemon_test"）
     */
    public static updateUnittestBuildGn(
        gnFilePath: string,
        testTargetName: string,
        testTargetContent: string,
        groupName: string
    ): void {
        Logger.info(`[GN Updater] 开始更新 unittest BUILD.gn: ${gnFilePath}`);
        
        if (fs.existsSync(gnFilePath)) {
            Logger.info(`[GN Updater] ✅ 找到现存 BUILD.gn，进行智能更新`);
            this.appendToExistingGn(gnFilePath, testTargetName, testTargetContent, groupName, 'unittest');
        } else {
            Logger.info(`[GN Updater] ⚠️ BUILD.gn 不存在，创建新文件`);
            this.createNewGn(gnFilePath, testTargetName, testTargetContent, groupName, 'unittest');
        }
    }

    /**
     * 更新或创建 fuzztest BUILD.gn
     */
    public static updateFuzztestBuildGn(
        gnFilePath: string,
        testTargetName: string,
        testTargetContent: string,
        groupName: string = 'fuzztest'
    ): void {
        Logger.info(`[GN Updater] 开始更新 fuzztest BUILD.gn: ${gnFilePath}`);
        
        if (fs.existsSync(gnFilePath)) {
            Logger.info(`[GN Updater] ✅ 找到现存 BUILD.gn，进行智能更新`);
            this.appendToExistingGn(gnFilePath, testTargetName, testTargetContent, groupName, 'fuzztest');
        } else {
            Logger.info(`[GN Updater] ⚠️ BUILD.gn 不存在，创建新文件`);
            this.createNewGn(gnFilePath, testTargetName, testTargetContent, groupName, 'fuzztest');
        }
    }

    /**
     * 追加到现有 GN 文件
     */
    private static appendToExistingGn(
        gnFilePath: string,
        testTargetName: string,
        testTargetContent: string,
        groupName: string,
        testType: 'unittest' | 'fuzztest'
    ): void {
        const content = fs.readFileSync(gnFilePath, 'utf-8');
        
        // 检查是否已经存在该测试目标
        const targetPattern = testType === 'unittest' 
            ? new RegExp(`ohos_unittest\\("${testTargetName}"\\)`, 'g')
            : new RegExp(`ohos_fuzztest\\("${testTargetName}"\\)`, 'g');
        
        if (targetPattern.test(content)) {
            Logger.info(`[GN Updater] ⚠️ 测试目标 "${testTargetName}" 已存在，跳过添加`);
            return;
        }

        // 查找 group 的位置
        const groupPattern = new RegExp(`group\\("${groupName}"\\)\\s*\\{[^}]*deps\\s*=\\s*\\[([^\\]]*)\\]`, 's');
        const groupMatch = content.match(groupPattern);

        if (groupMatch) {
            Logger.info(`[GN Updater] ✅ 找到 group("${groupName}")，更新 deps`);
            
            // 提取现有的 deps
            const existingDeps = groupMatch[1];
            const newDep = `:${testTargetName}`;
            
            // 检查是否已经在 deps 中
            if (existingDeps.includes(newDep)) {
                Logger.info(`[GN Updater] ⚠️ deps 中已包含 "${newDep}"，跳过`);
            } else {
                // 在最后一个 ] 之前插入测试目标定义和更新 deps
                const insertPosition = content.lastIndexOf(`group("${groupName}")`);
                
                // 构建新内容：测试目标 + 换行
                const newContent = 
                    content.substring(0, insertPosition) +
                    testTargetContent + '\n\n' +
                    content.substring(insertPosition);
                
                // 更新 group 的 deps
                const updatedContent = newContent.replace(
                    groupPattern,
                    (match, deps) => {
                        const trimmedDeps = deps.trim();
                        const newDeps = trimmedDeps 
                            ? `${trimmedDeps},\n    ${newDep},`
                            : `\n    ${newDep},`;
                        return match.replace(deps, newDeps);
                    }
                );
                
                fs.writeFileSync(gnFilePath, updatedContent, 'utf-8');
                Logger.info(`[GN Updater] ✅ 成功添加测试目标 "${testTargetName}" 到 BUILD.gn`);
            }
        } else {
            Logger.warn(`[GN Updater] ⚠️ 未找到 group("${groupName}")，追加到文件末尾`);
            
            // 直接追加测试目标和新的 group
            const newGroup = `
${testTargetContent}

group("${groupName}") {
  testonly = true
  deps = [
    ":${testTargetName}",
  ]
}
`;
            fs.writeFileSync(gnFilePath, content + '\n' + newGroup, 'utf-8');
            Logger.info(`[GN Updater] ✅ 追加测试目标和新 group 到 BUILD.gn`);
        }
    }

    /**
     * 创建新的 GN 文件
     */
    private static createNewGn(
        gnFilePath: string,
        testTargetName: string,
        testTargetContent: string,
        groupName: string,
        testType: 'unittest' | 'fuzztest'
    ): void {
        const currentYear = new Date().getFullYear();
        
        // 尝试从路径推断工程信息
        const projectInfo = this.inferProjectInfo(gnFilePath);
        
        const importStatements = testType === 'unittest'
            ? `import("//build/test.gni")\n${projectInfo.gniImport ? `import("${projectInfo.gniImport}")\n` : ''}`
            : `import("//build/config/features.gni")\nimport("//build/test.gni")\n${projectInfo.gniImport ? `import("${projectInfo.gniImport}")\n` : ''}`;

        const newContent = `# Copyright (c) ${currentYear} Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

${importStatements}

${testTargetContent}

group("${groupName}") {
  testonly = true
  deps = [
    ":${testTargetName}",
  ]
}
`;

        // 确保目录存在
        const dir = path.dirname(gnFilePath);
        if (!fs.existsSync(dir)) {
            fs.mkdirSync(dir, { recursive: true });
        }

        fs.writeFileSync(gnFilePath, newContent, 'utf-8');
        Logger.info(`[GN Updater] ✅ 创建新的 BUILD.gn: ${gnFilePath}`);
    }

    /**
     * 从路径推断工程信息
     */
    private static inferProjectInfo(gnFilePath: string): {
        subsystem: string;
        module: string;
        gniImport: string | null;
    } {
        // 从路径中提取信息，如：
        // /path/to/filemanagement_dfs_service/test/unittests/BUILD.gn
        // => subsystem: filemanagement, module: dfs_service
        
        const parts = gnFilePath.split(/[/\\]/);
        let projectDir = '';
        
        // 查找工程根目录（包含 bundle.json 的目录）
        for (let i = parts.length - 1; i >= 0; i--) {
            const testPath = parts.slice(0, i + 1).join(path.sep);
            if (fs.existsSync(path.join(testPath, 'bundle.json'))) {
                projectDir = parts[i];
                break;
            }
        }
        
        if (!projectDir) {
            return { subsystem: 'unknown', module: 'unknown', gniImport: null };
        }
        
        // 解析工程名称，如 filemanagement_dfs_service
        const match = projectDir.match(/^([a-z]+)_(.+)$/);
        if (match) {
            const subsystem = match[1];
            const module = match[2];
            
            // 尝试查找 .gni 文件
            const possibleGniFiles = [
                `${module}.gni`,
                `${projectDir}.gni`,
                `${subsystem}.gni`,
            ];
            
            const projectRootPath = parts.slice(0, parts.indexOf(projectDir) + 1).join(path.sep);
            for (const gniFile of possibleGniFiles) {
                const gniPath = path.join(projectRootPath, gniFile);
                if (fs.existsSync(gniPath)) {
                    return {
                        subsystem,
                        module,
                        gniImport: `"//foundation/${subsystem}/${projectDir}/${gniFile}"`
                    };
                }
            }
            
            return { subsystem, module, gniImport: null };
        }
        
        return { subsystem: 'unknown', module: 'unknown', gniImport: null };
    }

    /**
     * 从 BUILD.gn 中提取已存在的测试目标列表
     */
    public static extractExistingTargets(gnFilePath: string, testType: 'unittest' | 'fuzztest'): string[] {
        if (!fs.existsSync(gnFilePath)) {
            return [];
        }

        const content = fs.readFileSync(gnFilePath, 'utf-8');
        const pattern = testType === 'unittest'
            ? /ohos_unittest\("([^"]+)"\)/g
            : /ohos_fuzztest\("([^"]+)"\)/g;

        const targets: string[] = [];
        let match;
        while ((match = pattern.exec(content)) !== null) {
            targets.push(match[1]);
        }

        Logger.info(`[GN Updater] 从 ${gnFilePath} 提取到 ${targets.length} 个现有目标`);
        return targets;
    }
}

